package com.hhf.ftp.service.impl;

import com.hhf.ftp.service.FtpService;
import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.common.IOUtils;
import net.schmizz.sshj.connection.channel.direct.Session;
import net.schmizz.sshj.transport.verification.PromiscuousVerifier;
import net.schmizz.sshj.xfer.FileSystemFile;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.IOException;

/**
 * 各方法参数仅支持绝对路径
 */
@Service("ssh")
public class SshServiceImpl implements FtpService {
    private final static String HOME_DIR = System.getProperty("user.home");
    private SSHClient client;
    private Session session;
    private String cdPath;

    @Override
    public String connection(String username, String password, String ip, Integer port) throws IOException {
        if(port == null) {
            port = 22;
        }
        getClient(username, password, ip, port);
        return "SFTP connection success!";
    }

    @Override
    public void scpPut(String uploadFile, String directory, String encode) throws IOException {
        client.newSCPFileTransfer().upload(new FileSystemFile(uploadFile), directory);
    }

    @Override
    public void scpGet(String filename, String localPath, String encode) throws IOException {
        if(StringUtils.hasText(localPath)) {
            localPath = HOME_DIR;
        }
        client.newSCPFileTransfer().download(filename, new FileSystemFile(localPath));
    }

    @Override
    public void put(String uploadFile, String directory, String encode) throws IOException {
        scpPut(uploadFile,directory,encode);
    }

    @Override
    public void get(String filename, String localPath, String encode) throws IOException {
        scpGet(filename,localPath,encode);
    }

    @Override
    public void rm(String filePath, String encode) throws IOException {
        bash("rm -rf " + filePath);
    }

    /**
     * ssh模式下该命令单独执行不生效，可以使用诸如： bash 'cd /data/app && ls -l' 和其它命令连接在一起的命令一次性执行
     * @param dir
     * @throws IOException
     */
    @Override
    public void cd(String dir, String encode) throws IOException {
        cdPath = getPwd(dir);
    }

    /**
     * ssh模式下该命令单独执行不生效，可以使用诸如： bash 'cd /data/app && ls -l' 和其它命令连接在一起的命令一次性执行
     * @throws IOException
     */
    @Override
    public void cdup() throws IOException {
        if(cdPath == null) {
            cdPath = bash("pwd").replace("\n", "");
        }
        cdPath = cdPath.length()>1 ? cdPath.substring(0, cdPath.lastIndexOf("/")) : cdPath;;
    }

    @Override
    public void mkdir(String directory, String encode) throws IOException {
        bash("mkdir -p " + directory);
    }

    @Override
    public String ls(String dir, String encode) throws IOException {
        // 路径结尾统一去掉“/”
        cdPath = getPwd(dir);
        return bash("ls -al "+ cdPath);
    }

    @Override
    public String pwd(String encode) throws IOException {
        if(cdPath == null) {
            cdPath = bash("pwd").replace("\n", "");
        }
        return cdPath;
    }

    @Override
    public void mv(String from, String to, String encode) throws IOException {
        bash("mv " + from + " "+ to);
    }

    @Override
    public String bash(String cmdLine) throws IOException {
        Session.Command cmd = exec(cmdLine);
        return IOUtils.readFully(cmd.getInputStream()).toString();
    }

    @Override
    public String close() throws IOException {
        if (session != null) {
            session.close();
        }
        if (client != null) {
            client.disconnect();
        }
        return "Bye!";
    }

    private Session.Command exec(String cmdLine) throws IOException {
        session = client.startSession();
        Session.Command exec = session.exec(cmdLine);
        return exec;
    }
    private void getClient(String username, String password, String remoteHost, Integer port) throws IOException {
        SSHClient client = new SSHClient();
        client.addHostKeyVerifier(new PromiscuousVerifier());
        client.connect(remoteHost, port);
        client.authPassword(username, password);
        this.client = client;
    }

    private String getPwd(String dir) throws IOException {
        if(cdPath == null) {
            cdPath = bash("pwd").replace("\n", "");
        }
        if (StringUtils.hasText(dir)) {
            dir = dir.endsWith("/")  && dir.trim().length()>1 ? dir.substring(0, dir.length()-1) : dir;
            if(dir.startsWith("/")) {
                cdPath = dir;
            } else {
                cdPath = cdPath + "/" + dir;
            }
        }
        return cdPath;
    }

}
